﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Hzexe.Wechat.SharpSDK.Message.Request;
using Hzexe.Wechat.SharpSDK.Message.Response;

namespace Hzexe.Wechat.SharpSDK
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class WechatBase : IHttpHandler
    {
        /// <summary>
        /// 获取您的微信token
        /// </summary>
        protected abstract string token { get; }

        public virtual bool IsReusable
        {
            get { return true; }
        }
        /// <summary>
        /// 请求入口
        /// </summary>
        /// <param name="context"></param>
        public void ProcessRequest(HttpContext context)
        {
            string echostr = context.Request.QueryString["echostr"];
            string timestamp = context.Request.QueryString["timestamp"];
            string nonce = context.Request.QueryString["nonce"];
            string signature = context.Request.QueryString["signature"];

            if (context.Request.HttpMethod.Equals("GET"))
            {
                log.InfoFormat("get请求:{0}", context.Request.RawUrl);
                //get请求直接输出,验证只会给自己找不必要麻烦,并且还没有任意意义
                context.Response.ContentType = @"text/html";
                context.Response.Write(echostr + "");
            }
            else if (context.Request.HttpMethod.Equals("POST"))
            {
                //验证请求有效性,注意是对值进行验证
                string[] tarr = new string[] { nonce, timestamp, token };
                Array.Sort(tarr);

                var str1 = string.Join("", tarr);
                var sha1 = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str1, "SHA1");
                if (!sha1.ToLower().Equals(signature))
                {

                    log.WarnFormat("消息验证失败,请检测token是否设置正确,请求参数是:{0}", context.Request.RawUrl);
                    throw new HttpRequestValidationException("消息验证失败,请检测token是否设置正确");
                }

                var reqestPack = RequestMessageBase.Parse(context.Request.InputStream);
                log.InfoFormat("收到新的消息，编号：{0}\r\n消息{1}\r\n\r\n", reqestPack.MsgId, reqestPack);
                //调用处理程序获取处理结果
                var res = this.OnReceiveNewMsg(reqestPack);
                if (null != res)
                {
                    context.Response.ContentType = @"text/xml";
                    context.Response.ContentEncoding = Encoding.UTF8;
                    string xml = res.ToString();
                    context.Response.Write(xml);
                    //记录日志?
                    log.InfoFormat("回复消息编号为{0}消息{1}\r\n\r\n", reqestPack.MsgId, res);
                }
                else
                {
                    log.WarnFormat("请求,消息编号{0}，没有应答", reqestPack.MsgId);
                    throw new HttpException("无应答异常");
                }
            }
            else
            {
                throw new HttpException("不支持的请求方法");
            }
        }
        /// <summary>
        /// 收到文本消息的处理
        /// </summary>
        /// <param name="reqPackage">文本消息</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Text reqPackage);
        /// <summary>
        /// 收到图片消息消息的处理
        /// </summary>
        /// <param name="reqPackage">图片消息消息</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Image reqPackage);
        /// <summary>
        /// 收到地理位置消息的处理
        /// </summary>
        /// <param name="reqPackage">地理位置消息</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Location reqPackage);
        /// <summary>
        /// 收到链接消息的处理
        /// </summary>
        /// <param name="reqPackage">链接消息</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Link reqPackage);
        private ResponseMessageBase OnReceiveNewMsg(Hzexe.Wechat.SharpSDK.Message.Request.Message_In_Event reqPackage)
        {
            //对事件子类型进一步细化
            dynamic newpack = null; //新的包类型

            switch (reqPackage.Event)
            {
                //订阅
                case "subscribe":
                    newpack = reqPackage.CloneTo<Message_In_Event_Subscribe>();
                    break;
                case "unsubscribe":
                    newpack = reqPackage.CloneTo<Message_In_Event_unsubscribe>();
                    break;
                case "CLICK":
                    //菜单点击
                    newpack = reqPackage.CloneTo<Message_In_Event_MenuClicked>();
                    break;
                default:
                    break;
            }
            return this.OnReceiveNewMsg(newpack);

        }
        /// <summary>
        /// 收到新用户订阅消息的处理
        /// </summary>
        /// <param name="reqPackage">订阅消息体</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Event_Subscribe reqPackage);
        /// <summary>
        /// 收到用户取消订阅消息的处理
        /// </summary>
        /// <param name="reqPackage">退订消息体</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Event_unsubscribe reqPackage);
        /// <summary>
        /// 收到用户点击按钮的事件
        /// </summary>
        /// <param name="reqPackage">点击事件消息体</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Event_MenuClicked reqPackage);

        /// <summary>
        /// 收到语音消息
        /// </summary>
        /// <param name="reqPackage">消息体</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Voice reqPackage);
        /// <summary>
        /// 收到视频消息
        /// </summary>
        /// <param name="reqPackage">消息体</param>
        /// <returns>应答消息</returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Video reqPackage);

        /// <summary>
        /// 收到未知类型消息的处理
        /// </summary>
        /// <param name="reqPackage"></param>
        /// <returns></returns>
        protected abstract ResponseMessageBase OnReceiveNewMsg(Message_In_Unknown reqPackage);

        private ResponseMessageBase OnReceiveNewMsg(ResponseMessageBase reqPackage)
        {
            //未捕获的包会进入这个，代码级不出问题的话，不会出现这种情况
            return null;
        }

        static WechatBase()
        {
            log = log4net.LogManager.GetLogger(typeof(WechatBase));
        }

        //日志对象
        protected static readonly log4net.ILog log = null;
    }
}
